#!/usr/bin/python
#-*- coding: utf-8 -*-

from Tkinter import *
from Canvas import *
import sys
import random
import numpy as np
import collections

"""Numpy zur Matrix und Vektorrechnung benutzt"""

WIDTH  = 400 # width of canvas
HEIGHT = 400 # height of canvas

HPSIZE = 1 # double of point size (must be integer)
COLOR = "#0000FF" # blue

NOPOINTS = 1000

mat0 = np.eye(4) # 4x4 Einheitsmatrix, alle Operationen
mat1 = np.eye(4) # 4x4 Hilfsmatrix

points = [] # list of points (used by Canvas.delete(...))

pointFile = "cow_points.raw"

def quit(root=None):
    """ quit programm """
    if root==None:
        sys.exit(0)
    root._root().quit()
    root._root().destroy()

def draw():
    """ draw points """
#    for p in points:
 #       x, y = 
  #      p = can.create_oval(x-HPSIZE, y-HPSIZE, x+HPSIZE, y+HPSIZE, fill=COLOR, outline=COLOR)
   #     points.insert(0,p)
#    for i in range(1,NOPOINTS):
#        x, y = random.randint(1,WIDTH), random.randint(1,HEIGHT)
#	p = can.create_oval(x-HPSIZE, y-HPSIZE, x+HPSIZE, y+HPSIZE, fill=COLOR, outline=COLOR)
#	points.insert(0,p)

def rotYp():
    """ rotate counterclockwise around y axis """
    global NOPOINTS
    NOPOINTS += 100
    print "In rotYp: ", NOPOINTS 
    can.delete(*points)
    draw()

    

def rotYn():
    """ rotate clockwise around y axis """
    global NOPOINTS
    NOPOINTS -= 100
    print "In rotYn: ", NOPOINTS 
    can.delete(*points)
    draw()

def point (x, y=None, z=None, w=1.0):
    """For 3D, Gives 4x1 numpy vector"""
    l = len(x) if isinstance(x, collections.Iterable) else 1

    if l != 1: # x ist der Punkt
        if l==4:
            w = x[3]
        if 2 < l < 5: # len 3,4 OK
            x, y, z = x[0], x[1], x[2]
        else:
            raise AttributeError, "No valid Pointkoordinates %s" % str(x)

    if w != 1 and w != 0: # punkte im unendlichen w==0
        x = float(x) / w
        y = float(y) / w
        z = float(z) / w
        w = w/w
    assert w==1
    return np.array([x,y,z,w])

def translate(vec, points=points):
    """Verschiebt Punkte/Objekt durch Multiplikation mit 4x4 Matrix"""
    global mat0, mat1
    if not isinstance(vec, np.ndarray):
        raise AttributeError, "%s is no numpy.ndarray (vector)" % vec
    mat1[:,3] = vec
    print 'verschiebe in Ursprng, mat1'
    print "vTrans: ",  vTrans
    mat0 = mat0.dot(mat1) # Matrix veraendern
    points = map(mat0.dot, points) # Punkte veraendern
    mat1 = np.eye(4) # hilfsmatrix reset

def scale(xMin, xMax, # quelle Y-Achse
          yMin, yMax, # quelle Y-Achse
          zMin, zMax, # quelle Z-Achse
          uMin, Umax, # ziel X-Achse
          vMin, vMax, # ziel X-Achse
          wMin, wMax, # ziel X-Achse
          points=points):
    """Skaliert 3D homogene Punkte mit gegebener 4x4 Matrix"""
#    global mat0, mat1
    x = (uMax-Umin) / (xMax-Xmin)
    y = (vMax-vMin) / (yMax-yMin)
    z = (wMax-wMin) / (zMax-zMin)
    mat1 * (3,3,3,1)
    print mat1
    

    
if __name__ == "__main__":
    #check parameters
    if len(sys.argv) != 1:
       print "pointViewer.py"
       sys.exit(-1)
    
    # Punkt datei einlesen
    points = [map(float,line.split()) for line in file(pointFile)]

    # Boundingbox berrechnen
    bb = zip(*[ [min(lis), max(lis)] for lis in zip(*points)])
    # Ulli:  bb = [map(min, zip(*points)), map(max, zip(*points))] # map benutzt fur x,y,z listen

    # Zentrum der bb berrechnen
    pMin = point(bb[0]).T
    pMax = point(bb[1]).T
    pCenter = (pMin + pMax) * point(0.5, 0.5, 0.5)
    # Ulli: pCenter = [ (x[0] + x[1]) / 2.0 for x in zip(*bb)]
 
    # bb mit Zentrum in Ursprung verschieben
    # per Matrixmultiplikation
    vTrans = point(pCenter * point(-1, -1, -1, 1))
    translate(vTrans)
    
    # Skalierungsfaktor berrechnen um auf Länge 2x2 zu kommen [-1,1]R3
    # zip(*bb) -> packt jeweils min und max der 3 Achsen x,y,z zusammen: (xmin,xmax),(ymin,ymax)..
    scale = [2.0 /(x[1]-x[0]) for x in zip(*bb)] # gleichung umstellen: 2 = seitenlaenge * x
    # scale()
    # create main window

    print "bb:\t{}\nmin:\t{}\nmax:\t{}\ncenter:\t{}\nscale:\t{}".format(bb, pMin, pMax, pCenter, scale)
    mw = Tk()

    # create and position canvas and buttons
    cFr = Frame(mw, width=WIDTH, height=HEIGHT, relief="sunken", bd=1)
    cFr.pack(side="top")
    can = Canvas(cFr, width=WIDTH, height=HEIGHT)
    can.pack()
    bFr = Frame(mw)
    bFr.pack(side="left")
    bRotYn = Button(bFr, text="<-", command=rotYn)
    bRotYn.pack(side="left")
    bRotYp = Button(bFr, text="->", command=rotYp)
    bRotYp.pack(side="left")
    eFr = Frame(mw)
    eFr.pack(side="right")
    bExit = Button(eFr, text="Quit", command=(lambda root=mw: quit(root)))
    bExit.pack()

    # draw points
    draw()

    # start
    mw.mainloop()
